function [varargout] = BVQXtool(varargin)
% BVQXtool  - global UI based function for BVQXtools
%
% FORMAT:       BVQXtool
%
% Note: this function uses a global variable, BVQXti, that stores the
%       loaded files in the BVQXti.w field
%
%       it is generally deprecated to meddle with this variable
%       (unless you know what you're doing, that is)

% Version:  v0.8a
% Build:    9111317
% Date:     Nov-13 2009, 5:09 PM CET
% Author:   Jochen Weber, SCAN Unit, Columbia University, NYC, NY, USA
% URL/Info: http://wiki.brainvoyager.com/BVQXtools

% global variable
global BVQXti;
if isempty(BVQXti) || ...
   ~isstruct(BVQXti)

    % check availability of UI objects
    rp = get(0);
    ssz = rp.ScreenSize;
    if any(ssz(3:4) < 600)
        error( ...
            'BVQXtool:NoGUI', ...
            'UI screen not open or too small.' ...
        );
    end
    
    % delete prior objects
    delete(findobj('Tag', 'BVQXtool_MainFig'));

    % create BVQXtool internal variable
    BVQXti = struct;
    
    % sub field for config
    c = struct;
    c.btdown = [];
    c.incb = false;
    c.blockcb = {};
    c.linked = struct;
    c.linked.active = true;
    c.linked.scoord = [0, 0, 0];
    c.linked.tcoord = [0, 0, 0];
    c.ostype = ostype;
    c.ostypemac = strcmpi(c.ostype.machine, 'mac');
    c.rp = rp;
    BVQXti.c = c;
    
    % try to load standard LUT
    try
        BVQXti.lut = bless(BVQXfile([bvqxtools_path('lut') '/Standard_extended.olt']));
    catch
        BVQXti.lut = bless(BVQXfile('new:lut'));
    end
    BVQXti.VMRlut = [BVQXti.lut.Colors; 255 * ones(10, 3)];
    
    % sub field for children config
    cc = struct;
    h = struct;
    BVQXti.cc = cc;
    BVQXti.fcfg = struct;
    BVQXti.h = h;
    
    % sub field for workspace
    w = struct;
    BVQXti.w = w;
    
    % and for workspace control
    wc = struct;
    BVQXti.wc = wc;
    
    % create layered images
    BVQXti.tio.imSag = transimg(256, 256);
    addlayer(BVQXti.tio.imSag, uint8(zeros(256, 256)));
    BVQXti.tio.imCor = transimg(256, 256);
    addlayer(BVQXti.tio.imCor, uint8(zeros(256, 256)));
    BVQXti.tio.imTra = transimg(256, 256);
    addlayer(BVQXti.tio.imTra, uint8(zeros(256, 256)));
    BVQXti.tio.imSlZ = transimg(512, 512);
    addlayer(BVQXti.tio.imSlZ, uint8(zeros(512, 512)));
    
    % default VOI
    BVQXti.voi = 0;
    
    % create main fig
    try
        BVQXfigure([bvqxtools_path('tfg') '/BVQXtool.tfg']);
    catch
        error( ...
            'BVQXtool:NoGUI', ...
            'Error creating main figure.' ...
        );
    end
    
    % try loading all objects currently in workspace
    hasvmr = false;
    bvqxo = BVQXfile(0, 'objects');
    for oc = 2:numel(bvqxo)
        try
            if any(strcmpi(bvqxo(oc).S.Extensions{1}, ...
                {'dmr', 'fmr', 'glm', 'vmp', 'vmr', 'vtc'}))
                BVQXtool(0, 'openfile', BVQXfile(bvqxo(oc).L));
                if strcmpi(bvqxo(oc).S.Extensions{1}, 'vmr')
                    hasvmr = true;
                end
            end
        catch
            % do nothing
        end
    end
    if ~hasvmr
        try
            BVQXtool(0, 'openfile', [bvqxtools_path('colin'), filesep, 'colin.vmr']);
        catch
            % do nothing
        end
    end
    try
        BVQXtool(0, 'showpage', 1);
        BVQXtool(0, 'setslicepos');
    catch
        % do nothing
    end
end

% pre-set output
varargout = cell(1, nargout);

% check if already in callback
if BVQXti.c.incb
    
    % return if not clearcb call
    if nargin ~= 2 || ...
       ~ischar(varargin{2}) || ...
       ~strcmpi(varargin{2}(:)', 'clearcb')
        return;
    end
end

% UI call
if nargin > 1 && ...
    isa(varargin{1}, 'double') && ...
    numel(varargin{1}) == 1 && ...
    varargin{1} == 0 && ...
    ischar(varargin{2})

    % kind of call
    switch (lower(varargin{2}(:)'))
        
        % clear in-callback flag
        case {'clearcb'}
            BVQXti.c.incb = false;
            return;

        % set slicing position (update window)
        case {'setslicepos'}
            
            % get config from tag and try to get VMR link
            fMainFig = BVQXti.h.fMainFig;
            hMainFig = mlhandle(fMainFig);
            cc = BVQXti.fcfg;
            ch = BVQXti.h;
            
            % get position
            vsz  = 256;
            cPos = cc.cPos;
            nPos = get(hMainFig, 'CurrentPoint');
            cpg = ch.fMainFig.ShowPage('cur');
            fPos = [cc.SlicesPos; cc.ZSlicePos([1, 1, 1], :)];
            if cpg == 1
                fPos(4:6, :) = [];
                cobj = find(fPos(:, 1) <= nPos(1) & fPos(:, 2) <= nPos(2) & ...
                    fPos(:, 3) >  nPos(1) & fPos(:, 4) >  nPos(2));
            elseif cpg == 2
                fPos(1:3, 1:2) = 2000;
                cobj = find(fPos(:, 1) <= nPos(1) & fPos(:, 2) <= nPos(2) & ...
                    fPos(:, 3) >  nPos(1) & fPos(:, 4) >  nPos(2));
                if ~isempty(cobj)
                    cobj = cobj(1) + cc.ShowZoom - 1;
                end
            else
                cobj = [];
            end
    
            if ~isempty(cobj) && ...
                any(BVQXti.c.btdown == hMainFig)
                cp = nPos - fPos(cobj(1), 1:2);
                switch (cobj(1))
                    case {1}
                        cPos(1) = 128 - round(cp(1, 1)) * (vsz / 256);
                        cPos(2) = -128 + round(cp(1, 2)) * (vsz / 256);
                    case {2}
                        cPos(3) = 128 - round(cp(1, 1)) * (vsz / 256);
                        cPos(2) = -128 + round(cp(1, 2)) * (vsz / 256);
                    case {3}
                        cPos(3) = 128 - round(cp(1, 1)) * (vsz / 256);
                        cPos(1) = 128 - round(vsz - (cp(1, 2) + 1)) * (vsz / 256);
                    case {4}
                        cPos(1) = 128 - round(cp(1, 1)) * (vsz / 512);
                        cPos(2) = -128 + round(cp(1, 2)) * (vsz / 512);
                    case {5}
                        cPos(3) = 128 - round(cp(1, 1)) * (vsz / 512);
                        cPos(2) = -128 + round(cp(1, 2)) * (vsz / 512);
                    case {6}
                        cPos(3) = 128 - round(cp(1, 1)) * (vsz / 512);
                        cPos(1) = 128 - round(2 * vsz - (cp(1, 2) + 1)) * (vsz / 512);
                end
                BVQXti.fcfg.cPos = cPos;
            end

            % set position
            bvPos = 128 - cPos;
            if cpg == 1
                set(ch.SagLineX, 'YData', (128 + [cPos(2), cPos(2)]) / vsz);
                set(ch.SagLineY, 'XData', (128 - [cPos(1), cPos(1)]) / vsz);
                set(ch.CorLineX, 'YData', (128 + [cPos(2), cPos(2)]) / vsz);
                set(ch.CorLineY, 'XData', (128 - [cPos(3), cPos(3)]) / vsz);
                set(ch.TraLineX, 'YData', (128 + [cPos(1), cPos(1)]) / vsz);
                set(ch.TraLineY, 'XData', (128 - [cPos(3), cPos(3)]) / vsz);
                set(ch.Coord.TEdY, 'String', sprintf('%.0f', cPos(1)));
                set(ch.Coord.TEdZ, 'String', sprintf('%.0f', cPos(2)));
                set(ch.Coord.TEdX, 'String', sprintf('%.0f', cPos(3)));
                set(ch.Coord.VEdY, 'String', sprintf('%.0f', bvPos(1)));
                set(ch.Coord.VEdZ, 'String', sprintf('%.0f', bvPos(2)));
                set(ch.Coord.VEdX, 'String', sprintf('%.0f', bvPos(3)));
            elseif cpg == 2
                switch (cc.ShowZoom)
                    case {1}
                        set(ch.ZoomLineX, 'YData', (128 + [cPos(2), cPos(2)]) / vsz);
                        set(ch.ZoomLineY, 'XData', (128 - [cPos(1), cPos(1)]) / vsz);
                    case {2}
                        set(ch.ZoomLineX, 'YData', (128 + [cPos(2), cPos(2)]) / vsz);
                        set(ch.ZoomLineY, 'XData', (128 - [cPos(3), cPos(3)]) / vsz);
                    case {3}
                        set(ch.ZoomLineX, 'YData', (128 + [cPos(1), cPos(1)]) / vsz);
                        set(ch.ZoomLineY, 'XData', (128 - [cPos(3), cPos(3)]) / vsz);
                end
            end

            % sample data ?
            showz = cc.ShowZoom;
            show3 = (showz == 0);
            switch (showz)
                case {2}
                    bvPos(1) = bvPos(3);
                case {3}
                    bvPos = bvPos([3, 1]);
            end
            svals = [];
            frame = cc.frame;
            if ~isequal(cc.trans, eye(4))
                trans = cc.trans;
            else
                trans = [];
            end
            svar = cc.SlicesVar;
            if any([1, 2] == cpg)
                if numel(svar) == 1 && ...
                    isBVQXfile(svar)
                    ftype = lower(svar.Filetype);
                    volnum = round(ch.uiCTmpPosSl.Value);
                    ch.uiCTmpPosEd.String = sprintf('%d', volnum);
                    if show3
                        [sag, cor, tra] = svar.SliceData3D(cPos([3, 1, 2]), ...
                            struct('mapvol', volnum, 'method', 'linear', ...
                            'frame', frame, 'trans', trans));
                    else
                        diropt = cc.dirorder{showz};
                        zoom = svar.SliceData3D(cPos([3, 1, 2]), ...
                            struct('mapvol', volnum, 'method', 'linear', ...
                            'dir', diropt, 'step', 0.5, 'trans', trans, ...
                            'frame', frame));
                        if any(strcmp(ftype, {'hdr', 'vmr', 'vtc'}))
                            zoom = min(255, max(0, zoom));
                        end
                    end
                    if strcmp(ftype, 'vtc')
                        voxc = bvcoordconv(cPos([3, 1, 2]), 'tal2bvx', ...
                            svar.BoundingBox);
                        if ~isnan(voxc)
                            timc = double(svar.VTCData(:, voxc));
                        else
                            timc = zeros(svar.NrOfVolumes, 1);
                        end
                        tmmm = minmaxmean(timc, 4);
                        tmd = (tmmm(2) - tmmm(1)) + eps;
                        set(ch.TCPlot.Children, 'Visible', 'on', ...
                            'XData', 1:numel(timc), 'YData', double(timc));
                        ch.TCPlot.XLim = [0, numel(timc) + 1];
                        ch.TCPlot.YLim = ...
                            [floor(tmmm(1) - 0.05 * tmd), ceil(tmmm(2) + 0.05 * tmd)];
                        ch.TCPlot.Visible = 'on';
                    else
                        set(ch.TCPlot.Children, 'Visible', 'off');
                        ch.TCPlot.Visible = 'off';
                    end
                    if show3
                        bvPos = round(bvPos + 1);
                        mxs = minmaxmean([sag, cor, tra]);
                        svals = sag(bvPos(2), bvPos(1));
                    else
                        bvPos = round(2 * bvPos + 1);
                        mxs = minmaxmean(zoom);
                        svals = zoom(bvPos(2), bvPos(1));
                    end
                    if mxs(2) > 255
                        if show3
                            sag = (255 ./ mxs(2)) .* sag;
                            cor = (255 ./ mxs(2)) .* cor;
                            tra = (255 ./ mxs(2)) .* tra;
                        else
                            zoom = (255 ./ mxs(2)) .* zoom;
                        end
                    elseif mxs(1) < 0 && ...
                       (mxs(2) - mxs(1)) <= 112
                        adt = 2 .^ ceil(log2(max(abs(mxs(1:2)))));
                        mxd = 112 ./ (eps + adt);
                        if show3
                            sag = 113 + mxd .* sag;
                            cor = 113 + mxd .* cor;
                            tra = 113 + mxd .* tra;
                        else
                            zoom = 113 + mxd .* zoom;
                        end
                    elseif mxs(1) >= 0 && ...
                        mxs(2) > 0 && ...
                        mxs(2) <= (1 + eps)
                        if show3
                            sag = 255 .* sag;
                            cor = 255 .* cor;
                            tra = 255 .* tra;
                        else
                            zoom = 255 .* zoom;
                        end
                    elseif strcmp(ftype, 'vmr')
                        if mxs(2) > 225.1
                            if show3
                                cols = (sag > 225);
                                colv = round(min(30, max(1, sag(cols) - 225)));
                                sag = (255 / 225) .* sag;
                                zoomg = sag;
                                zoomb = sag;
                                sag(cols) = BVQXti.VMRlut(colv, 1);
                                zoomg(cols) = BVQXti.VMRlut(colv, 2);
                                zoomb(cols) = BVQXti.VMRlut(colv, 3);
                                sag = cat(3, sag, zoomg, zoomb);
                                cols = (cor > 225);
                                colv = round(min(30, max(1, cor(cols) - 225)));
                                cor = (255 / 225) .* cor;
                                zoomg = cor;
                                zoomb = cor;
                                cor(cols) = BVQXti.VMRlut(colv, 1);
                                zoomg(cols) = BVQXti.VMRlut(colv, 2);
                                zoomb(cols) = BVQXti.VMRlut(colv, 3);
                                cor = cat(3, cor, zoomg, zoomb);
                                cols = (tra > 225);
                                colv = round(min(30, max(1, tra(cols) - 225)));
                                tra = (255 / 225) .* tra;
                                zoomg = tra;
                                zoomb = tra;
                                tra(cols) = BVQXti.VMRlut(colv, 1);
                                zoomg(cols) = BVQXti.VMRlut(colv, 2);
                                zoomb(cols) = BVQXti.VMRlut(colv, 3);
                                tra = cat(3, tra, zoomg, zoomb);
                            else
                                cols = (zoom > 225);
                                colv = round(min(30, max(1, zoom(cols) - 225)));
                                zoom = (255 / 225) .* zoom;
                                zoomg = zoom;
                                zoomb = zoom;
                                zoom(cols) = BVQXti.VMRlut(colv, 1);
                                zoomg(cols) = BVQXti.VMRlut(colv, 2);
                                zoomb(cols) = BVQXti.VMRlut(colv, 3);
                                zoom = cat(3, zoom, zoomg, zoomb);
                            end
                        end
                    end
                else
                    sag = uint8(zeros(256, 256));
                    cor = sag;
                    tra = sag;
                end

                % set image data
                if cpg == 1
                    setlayer(BVQXti.tio.imSag, 1, uint8(round(sag)));
                    setlayer(BVQXti.tio.imCor, 1, uint8(round(cor)));
                    setlayer(BVQXti.tio.imTra, 1, uint8(round(tra)));
                elseif cpg == 2
                    setlayer(BVQXti.tio.imSlZ, 1, uint8(round(zoom)));
                end

                % remove stats layers
                if show3
                    if numel(BVQXti.tio.imSag.Layer) > 1
                        dellayer(BVQXti.tio.imSag, 2:numel(BVQXti.tio.imSag.Layer));
                        dellayer(BVQXti.tio.imCor, 2:numel(BVQXti.tio.imCor.Layer));
                        dellayer(BVQXti.tio.imTra, 2:numel(BVQXti.tio.imTra.Layer));
                    end
                else
                    if numel(BVQXti.tio.imSlZ.Layer) > 1
                        dellayer(BVQXti.tio.imSlZ, 2:numel(BVQXti.tio.imSlZ.Layer));
                    end
                end
                
                if numel(cc.StatsVar) == 1 && ...
                    ~isempty(cc.StatsVarIdx)
                    svi = cc.StatsVarIdx;
                    if ch.Interpolate.Value ~= 0
                        imeth = 'cubic';
                    else
                        imeth = 'nearest';
                    end
                    tls = double(ch.Stats.PosTail.Value ~= 0) + ...
                        2 * double(ch.Stats.NegTail.Value ~= 0);
                    svals(1, numel(svi) + 1) = 0;
                    for svc = 1:numel(svi)

                        % get map thresholds
                        sm = cc.StatsVarThr;
                        try
                            lut = BVQXti.lut.Colors(:, :);
                        catch
                            lut = BVQXti.VMRlut(1:20, :);
                        end

                        % get stats
                        aval = cc.StatsVarAlpha;
                        if show3
                            [scsag, sccor, sctra] = ...
                                cc.StatsVar.SliceData3D(cPos([3, 1, 2]), ...
                                struct('method', imeth, 'mapvol', svi(svc), ...
                                'trans', trans, 'frame', frame));
                            svals(svc + 1) = scsag(bvPos(2), bvPos(1));

                            % tails
                            scsag = threshmapc(scsag, sm(1), sm(2), tls);
                            sccor = threshmapc(sccor, sm(1), sm(2), tls);
                            sctra = threshmapc(sctra, sm(1), sm(2), tls);
                            if aval > 0
                                scsagc = aval .* double(scsag ~= 0);
                                sccorc = aval .* double(sccor ~= 0);
                                sctrac = aval .* double(sctra ~= 0);
                            else
                                aval = abs(aval);
                                scsagc = min(1, aval .* abs(scsag));
                                sccorc = min(1, aval .* abs(sccor));
                                sctrac = min(1, aval .* abs(sctra));
                            end
                            setlayer(BVQXti.tio.imSag, 1 + svc, ...
                                threshlutc(scsag, lut), scsagc);
                            setlayer(BVQXti.tio.imCor, 1 + svc, ...
                                threshlutc(sccor, lut), sccorc);
                            setlayer(BVQXti.tio.imTra, 1 + svc, ...
                                threshlutc(sctra, lut), sctrac);
                        else
                            diropt = cc.dirorder{showz};
                            sczoom = cc.StatsVar.SliceData3D(cPos([3, 1, 2]), ...
                                struct('method', imeth, 'mapvol', svi(svc), ...
                                'dir', diropt, 'step', 0.5, 'trans', trans, ...
                                'frame', frame));
                            svals(svc + 1) = sczoom(bvPos(2), bvPos(1));

                            % tails
                            sczoom = threshmapc(sczoom, sm(1), sm(2), tls);
                            if aval > 0
                                sczoomc = aval .* double(sczoom ~= 0);
                            else
                                aval = abs(aval);
                                sczoomc = min(1, aval .* abs(sczoom));
                            end
                            setlayer(BVQXti.tio.imSlZ, 1 + svc, ...
                                threshlutc(sczoom, lut), sczoomc);
                        end
                    end
                end

                if show3
                    render(BVQXti.tio.imSag)
                    render(BVQXti.tio.imCor)
                    render(BVQXti.tio.imTra)
                else
                    render(BVQXti.tio.imSlZ)
                end
                
                % set sampled values
                if ~isempty(svals)
                    ch.Coord.SVal.String = sprintf('Sampled Values: [%g%s]', ...
                        svals(1), sprintf(' %.4f', svals(2:end)));
                else
                    ch.Coord.SVal.String = 'Sampled Values: [ ]';
                end
            end
            
            % update GLM beta plot?
            if isBVQXfile(svar, 'vmr') && ...
                isfield(svar.Handles, 'PlotHandles')
                ph = svar.Handles.PlotHandles;
                if numel(ph.BetaPlotOpts.ax) == 1 && ...
                    ishandle(ph.BetaPlotOpts.ax) && ...
                    numel(ph.BetaPlotGLM) == 1 && ...
                    isBVQXfile(ph.BetaPlotGLM, 'glm')
                    try
                        ph.BetaPlotGLM.PlotBetas(cPos([3, 1, 2]), ...
                            ph.BetaPlotOpts);
                    catch
                        % do nothing
                    end
                end
            end
            
        % button pressed in VMR window
        case {'mainwindowbtdown'}
            
            % add current figure to list of btdown
            BVQXti.c.btdown = [BVQXti.c.btdown(:)', gcbf];
            
            % update window
            BVQXtool(0, 'setslicepos');
            
        % motion while button pressed
        case {'mainwindowbtmove'}
            
            % check if bt IS down
            if ~any(BVQXti.c.btdown == gcbf)
                return;
            end
            
            % update window
            BVQXtool(0, 'setslicepos');
            
        % button released
        case {'mainwindowbtup'}
            
            % remove btdown entry
            BVQXti.c.btdown(BVQXti.c.btdown == gcbf) = [];
            
        % main window keypress
        case {'mainwindowkeypress'}
            
            % check figure and event structure
            if nargin < 4 || ...
                numel(varargin{3}) ~= 1 || ...
               ~ishandle(varargin{3}(1)) || ...
                numel(varargin{4}) ~= 1 || ...
               ~isstruct(varargin{4})
                return;
            end
            
            % get figure, key, modifiers and resulting character
            ustr = BVQXti.fcfg;
            ustr.h = BVQXti.h;
            ke = varargin{4};
            kk = ke.Key;
            mn = ke.Modifier;
            
            % modifier pressed
            km = false(1, 3);
            if ~isempty(mn)
                try
                    km = [ ...
                        any(strcmpi('alt', mn)), ...
                        any(strcmpi('control', mn)), ...
                        any(strcmpi('shift', mn))];
                catch
                    % do nothing
                end
            end
            
            % handle events without modifiers
            if ~any(km)
                switch (lower(kk))

                    % toggle lines on/off for VMR Browser
                    case {'a'}
                        sl = ~ustr.ShowLines;
                        BVQXti.fcfg.ShowLines = sl;
                        if sl
                            sl = 'on';
                        else
                            sl = 'off';
                        end
                        if BVQXti.fcfg.ShowZoom == 0
                            set([ustr.h.CorLineX, ...
                                ustr.h.CorLineY, ...
                                ustr.h.SagLineX, ...
                                ustr.h.SagLineY, ...
                                ustr.h.TraLineX, ...
                                ustr.h.TraLineY], 'Visible', sl);
                            set(ustr.h.ZoomLineX, 'Visible', 'off');
                            set(ustr.h.ZoomLineY, 'Visible', 'off');
                        else
                            set([ustr.h.CorLineX, ...
                                ustr.h.CorLineY, ...
                                ustr.h.SagLineX, ...
                                ustr.h.SagLineY, ...
                                ustr.h.TraLineX, ...
                                ustr.h.TraLineY], 'Visible', 'off');
                            set(ustr.h.ZoomLineX, 'Visible', sl);
                            set(ustr.h.ZoomLineY, 'Visible', sl);
                        end
                        
                    % interpolation
                    case {'i'}
                        BVQXti.h.Interpolate.Value = ...
                            double(BVQXti.h.Interpolate.Value == 0);
                        BVQXtool(0, 'setslicepos');
                        
                    % zoomed view
                    case {'t'}
                        BVQXti.fcfg.ShowZoom = mod(BVQXti.fcfg.ShowZoom + 1, 4);
                        if BVQXti.fcfg.ShowZoom == 0
                            BVQXtool(0, 'showpage', 1);
                        else
                            BVQXtool(0, 'showpage', 2);
                        end

                    % cursor movements
                    case {'downarrow'}
                        BVQXti.fcfg.cPos(2) = ...
                            min(127.999, max(-128, BVQXti.fcfg.cPos(2) - 1));
                        BVQXtool(0, 'setslicepos');
                    case {'leftarrow'}
                        BVQXti.fcfg.cPos(3) = ...
                            min(127.999, max(-128, BVQXti.fcfg.cPos(3) + 1));
                        BVQXtool(0, 'setslicepos');
                    case {'rightarrow'}
                        BVQXti.fcfg.cPos(3) = ...
                            min(127.999, max(-128, BVQXti.fcfg.cPos(3) - 1));
                        BVQXtool(0, 'setslicepos');
                    case {'uparrow'}
                        BVQXti.fcfg.cPos(2) = ...
                            min(127.999, max(-128, BVQXti.fcfg.cPos(2) + 1));
                        BVQXtool(0, 'setslicepos');

                end

            % handle events with ALT
            elseif km(1)
                switch (lower(kk))
                    case {'downarrow'}
                        BVQXti.fcfg.StatsVarAlpha = ...
                            max(-2, BVQXti.fcfg.StatsVarAlpha - 0.1);
                        BVQXtool(0, 'setslicepos');
                    case {'uparrow'}
                        BVQXti.fcfg.StatsVarAlpha = ...
                            min(1, BVQXti.fcfg.StatsVarAlpha + 0.1);
                        BVQXtool(0, 'setslicepos');
                end

            % handle events with CTRL
            elseif km(2)

            % handle events with SHIFT
            elseif km(3)
                switch (lower(kk))

                    % cursor movements
                    case {'downarrow'}
                        BVQXti.fcfg.cPos(1) = ...
                            min(127.999, max(-128, BVQXti.fcfg.cPos(1) - 1));
                        BVQXtool(0, 'setslicepos');
                    case {'uparrow'}
                        BVQXti.fcfg.cPos(1) = ...
                            min(127.999, max(-128, BVQXti.fcfg.cPos(1) + 1));
                        BVQXtool(0, 'setslicepos');
                end
            end
            
        % show a page
        case {'showpage'}
            if nargin < 3 || ...
               ~isa(varargin{3}, 'double') || ...
                numel(varargin{3}) ~= 1
                return;
            end
            ustr = BVQXti.fcfg;
            ustr.h = BVQXti.h;
            sl = ustr.ShowLines;
            if sl > 0
                sl = 'on';
            else
                sl = 'off';
            end
            BVQXti.h.fMainFig.ShowPage(varargin{3}, 'norefresh');
            BVQXtool(0, 'setslicepos');
            if varargin{3} == 1
                sl1 = sl;
                sl2 = 'off';
            elseif varargin{3} == 2
                sl1 = 'off';
                sl2 = sl;
            else
                sl1 = 'off';
                sl2 = 'off';
            end
            set([ustr.h.CorLineX, ...
                ustr.h.CorLineY, ...
                ustr.h.SagLineX, ...
                ustr.h.SagLineY, ...
                ustr.h.TraLineX, ...
                ustr.h.TraLineY], 'Visible', sl1);
            set([ustr.h.ZoomLineX, ...
                ustr.h.ZoomLineY], 'Visible', sl2);
            set([get(ustr.h.CorLineX, 'Parent'), ...
                get(ustr.h.SagLineX, 'Parent'), ...
                get(ustr.h.TraLineX, 'Parent'), ...
                get(ustr.h.ZoomLineX, 'Parent')], 'Visible', 'off');
                return;
            
        % set stats threshold
        case {'setstatthr'}
            
            % value text boxes
            if nargin < 3
                lowt = get(BVQXti.h.Stats.LThresh, 'String');
                uppt = get(BVQXti.h.Stats.UThresh, 'String');
                try
                    lowt = str2double(lowt);
                    uppt = str2double(uppt);
                catch
                    set(BVQXti.h.Stats.LThresh, 'String', ...
                        sprintf('%.3f', BVQXti.fcfg.StatsVarThr(1)));
                    set(BVQXti.h.Stats.UThresh, 'String', ...
                        sprintf('%.3f', BVQXti.fcfg.StatsVarThr(2)));
                    return;
                end
                BVQXti.fcfg.StatsVarThr = [lowt, uppt];
                BVQXtool(0, 'setslicepos');
               
            % p-value dropdown
            elseif ischar(varargin{3}) && ...
                strcmpi(varargin{3}, 'pval')
            
                pval = str2double(BVQXti.h.Stats.PThresh.String{BVQXti.h.Stats.PThresh.Value});
                if BVQXti.h.Stats.NegTail.Value ~= 0 && ...
                    BVQXti.h.Stats.PosTail.Value ~= 0
                    ttld = 0.5;
                else
                    ttld = 1;
                end
                ttud = 0.02 * ttld;
                switch (BVQXti.fcfg.StatsVarPar{1})
                    case {'t'}
                        lthr = -tinv(ttld * pval, BVQXti.fcfg.StatsVarPar{2});
                        uthr = -tinv(ttud * pval, BVQXti.fcfg.StatsVarPar{2});
                    case {'F'}
                        lthr = finv(1 - pval, BVQXti.fcfg.StatsVarPar{2}, ...
                            BVQXti.fcfg.StatsVarPar{3});
                        uthr = finv(1 - 0.01 * pval, BVQXti.fcfg.StatsVarPar{2}, ...
                            BVQXti.fcfg.StatsVarPar{3});
                    case {'r'}
                        lthr = correlinvtstat(-tinv(ttld * pval, ...
                            BVQXti.fcfg.StatsVarPar{2}), ...
                            BVQXti.fcfg.StatsVarPar{2} + 2);
                        uthr = correlinvtstat(-tinv(ttud * pval, ...
                            BVQXti.fcfg.StatsVarPar{2}), ...
                            BVQXti.fcfg.StatsVarPar{2} + 2);
                    otherwise
                        lthr = NaN;
                end
                if ~isnan(lthr)
                    BVQXti.fcfg.StatsVarThr = [lthr, uthr];
                    set(BVQXti.h.Stats.LThresh, 'String', ...
                        sprintf('%.3f', lthr));
                    set(BVQXti.h.Stats.UThresh, 'String', ...
                        sprintf('%.3f', uthr));
                    BVQXtool(0, 'setslicepos');
                end
            end
            
        % cluster table
        case {'clustertable'}
            
            % block further clustertable
            if any(strcmp('clustertable', BVQXti.c.blockcb))
                return;
            end
            BVQXti.c.blockcb{end+1} = 'clustertable';
            
            % only for VMPs
            if ~isBVQXfile(BVQXti.fcfg.StatsVar, 'vmp')
                BVQXti.c.blockcb(strcmp('clustertable', BVQXti.c.blockcb)) = [];
                return;
            end
            stvar = BVQXti.fcfg.StatsVar;
            mapno = BVQXti.h.uiCStatCont.Value(end);
            ctopt = struct( ...
                'localmax', round(1000 ./ (stvar.Resolution .^ 3)), ...
                'localmin', round(125 ./ (stvar.Resolution .^ 3)), ...
                'showneg', BVQXti.h.Stats.NegTail.Value > 0, ...
                'showpos', BVQXti.h.Stats.PosTail.Value > 0, ...
                'minsize', 1, ...
                'mni2tal', BVQXti.h.Stats.MNI2TAL.Value > 0, ...
                'tdclient', BVQXti.h.Stats.TDClient.Value > 0, ...
                'pbar', BVQXti.h.Progress);
            if BVQXti.h.Stats.UsekThr.Value > 0
                try
                    ctopt.minsize = str2double(get(BVQXti.h.Stats.kThresh, 'String'));
                    BVQXti.fcfg.StatsVar.Map(mapno).EnableClusterCheck = 1;
                catch
                    % do nothing
                end
            else
                try
                    BVQXti.fcfg.StatsVar.Map(mapno).EnableClusterCheck = 0;
                catch
                    % do nothing
                end
            end
            BVQXti.h.Progress.Visible = 'on';
            [clusters, ttab, clmap, clvoi] = stvar.ClusterTable( ...
                mapno, BVQXti.fcfg.StatsVarThr(1), ctopt);
            BVQXti.h.Progress.Visible = 'off';
            if isBVQXfile(BVQXti.voi)
                BVQXti.voi.ClearObject;
            end
            BVQXti.voi = clvoi;
            vnames = clvoi.VOINames;
            for cc = 1:numel(vnames)
                if strcmpi(clusters(cc).localmax, 'l')
                    lmaxs = ' (local max.)';
                else
                    lmaxs = '';
                end
                vnames{cc} = sprintf('%s - %d voxel(s)%s', vnames{cc}, ...
                    clvoi.VOI(cc).NrOfVoxels, lmaxs);
            end
            BVQXti.h.uiCStatClust.Value = [];
            BVQXti.h.uiCStatClust.String = vnames;
            if ~isempty(vnames)
                BVQXti.h.uiCStatClust.Enable = 'on';
                BVQXti.h.uiCStatClusTb.String = ttab;
            else
                BVQXti.h.uiCStatClust.Enable = 'off';
            end
            BVQXti.c.blockcb(strcmp('clustertable', BVQXti.c.blockcb)) = [];
            BVQXtool(0, 'setslicepos');
            
        % set cluster
        case {'setcluster'}
            
            % get VOI cluster(s)
            try
                cl = BVQXti.voi.VOI(BVQXti.h.uiCStatClust.Value);
            catch
                % do nothing
            end
            
            % for one cluster
            if numel(cl) == 1
                
                BVQXti.fcfg.cPos = cl.Voxels(1, [2, 3, 1]);
                BVQXtool(0, 'setslicepos');
                
            % multiple clusters
            else
            end
            
        % alphasim
        case {'alphasim'}
            
            % block further alphasim calls
            if any(strcmp('alphasim', BVQXti.c.blockcb))
                return;
            end
            BVQXti.c.blockcb{end+1} = 'alphasim';
            
            % only works reasonably for VMP files
            stvar = BVQXti.fcfg.StatsVar;
            if ~isBVQXfile(stvar, 'vmp')
                BVQXti.c.blockcb(strcmp('alphasim', BVQXti.c.blockcb)) = [];
                return;
            end
            res = stvar.Resolution;
            
            % get smoothing kernel size in mm
            smkmm = inputdlg( ...
                {'Please enter the smoothing kernel size:'}, ...
                'BVQXtool user input', 1, {' 6'});
            try
                smkmm = str2double(smkmm) / res;
            catch
                warning( ...
                    'BVQXtool:BadInput', ...
                    'Invalid user input.' ...
                );
                BVQXti.c.blockcb(strcmp('alphasim', BVQXti.c.blockcb)) = [];
                return;
            end
            niter = inputdlg( ...
                {'Please enter the number of iterations:'}, ...
                'BVQXtool user input', 1, {' 1000'});
            try
                niter = round(str2double(niter));
            catch
                warning( ...
                    'BVQXtool:BadInput', ...
                    'Invalid user input.' ...
                );
                BVQXti.c.blockcb(strcmp('alphasim', BVQXti.c.blockcb)) = [];
                return;
            end
            
            % get map size and create mask
            try
                mvol = stvar.Map(BVQXti.h.uiCStatCont.Value(1)).VMPData ~= 0;
            catch
                mvol = stvar.Map(1).VMPData ~= 0;
            end
            
            % run alphasim
            alphasthr = [0.05, 0.01, 0.005, 0.002, 0.001, 0.0005, 0.0001];
            BVQXti.h.Progress.Visible = 'on';
            alphasout = alphasim(size(mvol), struct( ...
                'mask', mvol, 'fwhm', smkmm([1, 1, 1]), 'niter', niter, ...
                'thr', alphasthr, 'pbar', BVQXti.h.Progress));
            BVQXti.h.Progress.Visible = 'off';
            
            % output result in console
            disp(' ');
            disp('alphasim output for');
            disp(sprintf(' - %d-by-%d-by-%d volume with %d voxels', ...
                [size(mvol), sum(mvol(:))]));
            disp(sprintf(' - %.1fmm smoothing kernel', smkmm * res));
            disp(sprintf(' - %d iterations', niter));
            disp(repmat('-', 1, 72));
            for tc = 1:numel(alphasthr)
                disp(sprintf('FWE(p < 0.05) k for uncorr. p < %g : %d voxels', ...
                    alphasthr(tc), findfirst(alphasout{tc}(:,end) < 0.05)));
            end
            disp(' ');
            BVQXti.c.blockcb(strcmp('alphasim', BVQXti.c.blockcb)) = [];
            
        % close
        case {'close'}
            
            % are you sure...?
            if nargin < 3
                asw = questdlg('Are you sure you want to close BVQXtool?', ...
                    'BVQXtool close request...', 'No', 'Yes', 'Yes & Clear', 'Yes');
                if strcmpi(asw, 'no')
                    return;
                end
            elseif ischar(varargin{3})
                asw = varargin{3}(:)';
            else
                asw = 'Yes';
            end
            
            % close the figure
            if ~isempty(BVQXti.h.fChild)
                try
                    delete(BVQXti.h.fChild);
                catch
                    % do nothing
                end
            end
            try
                BVQXti.h.fMainFig.Delete;
            catch
                % do nothing
            end
            delete(findobj('Tag', 'BVQXtool_MainFig'));
            
            % and clear storage
            if strcmpi(asw, 'yes & clear')
                sf = fieldnames(BVQXti.wc);
                for sfc = 1:numel(sf)
                    if BVQXti.wc.(sf{sfc}) && ...
                        isfield(BVQXti.w, sf{sfc}) && ...
                        numel(BVQXti.w.(sf{sfc})) == 1 && ...
                        isBVQXfile(BVQXti.w.(sf{sfc}), true)
                        BVQXti.w.(sf{sfc}).ClearObject;
                    end
                end
            end
            
            % clear LUT
            try
                BVQXti.lut.ClearObject;
            catch
                % do nothing
            end
            
            % clear VOI
            try
                if isBVQXfile(BVQXti.voi)
                    BVQXti.voi.ClearObject;
                end
            catch
                % do nothing
            end
            
            % clear transimg objects
            delete(BVQXti.tio.imSag);
            delete(BVQXti.tio.imCor);
            delete(BVQXti.tio.imTra);
            delete(BVQXti.tio.imSlZ);
            
            % clear global variable
            BVQXti(1:end) = [];
            return;
            
        % create object
        case {'createobj'}
            varargout{1} = class(bt_createobj, 'BVQXtool');
            
        % set window pos from text input
        case {'mainwindowsetpos'}
            
            % get config from tag and try to get VMR link
            cc = BVQXti.fcfg;
            ch = BVQXti.h;
            
            % what object
            eobj = [ ...
                ch.Coord.TEdY, ch.Coord.TEdZ, ch.Coord.TEdX, ...
                ch.Coord.VEdY, ch.Coord.VEdZ, ch.Coord.VEdX];
            cobj = find(eobj == gcbo);
            if isempty(cobj)
                return;
            end
            
            % parse string
            cPos = cc.cPos;
            cstr = get(eobj(cobj), 'String');
            if cobj <= 3 && ...
               (isempty(regexpi(cstr, '^[\+\-]?\d+(\.\d)?$')) ||  ...
                abs(str2double(cstr(:)')) > 128)
                cstr = sprintf('%.0f', cPos(cobj));
                set(eobj(cobj), 'String', cstr);
            elseif cobj > 3 && ...
               (isempty(regexpi(cstr, '^[\+\-]?\d+(\.\d)?$')) ||  ...
                str2double(cstr(:)') < 0 || ...
                str2double(cstr(:)') > 255.999)
                cstr = sprintf('%.0f', 128 - cPos(cobj - 3));
                set(eobj(cobj), 'String', cstr);
            else
                switch (cobj)
                    case {1, 2, 3}
                        cPos(cobj) = str2double(cstr(:)');
                    case {4, 5, 6}
                        cPos(cobj - 3) = 128 - str2double(cstr(:)');
                    otherwise
                        return;
                end
                BVQXti.fcfg.cPos = cPos;
                BVQXtool(0, 'setslicepos');
            end
            
        % open file
        case {'openfile'}
            BVQXti.c.incb = true;
            try
                if nargin > 2
                    if numel(varargin{3}) ~= 1 || ...
                       ~isBVQXfile(varargin{3})
                        [f, toolloaded] = BVQXfile(varargin{3});
                    else
                        f = varargin{3};
                        fstr = struct(f);
                        svars = BVQXti.h.uiCVar.UserData;
                        for loc = 1:size(svars, 1)
                            fstrt = struct(svars{loc, 4});
                            if fstr.L == fstrt.L
                                BVQXti.h.uiCVar.Value = loc;
                                BVQXti.c.incb = false;
                                BVQXtool(0, 'setcvar');
                                return;
                            end
                        end
                        lfld = fieldnames(BVQXti.w);
                        for loc = 1:numel(lfld)
                            fstrt = struct(BVQXti.w.(lfld{loc}));
                            if fstr.L == fstrt.L
                                BVQXti.c.incb = false;
                                return;
                            end
                        end
                        toolloaded = false;
                    end
                else
                    [f, toolloaded] = BVQXfile('*.*');
                end
                if numel(f) ~= 1 || ...
                   ~isBVQXfile(f, true)
                    BVQXti.c.incb = false;
                    return;
                end
            catch
                BVQXti.c.incb = false;
                error( ...
                    'BVQXtool:BadUserInput', ...
                    'Invalid file chosen.' ...
                );
            end
            
            [fn{1:3}] = fileparts(f.FilenameOnDisk);
            vn = makelabel([upper(fn{3}) '_' fn{2}]);
            BVQXti.w.(vn) = f;
            BVQXti.wc.(vn) = toolloaded;
            if toolloaded
                bless(f);
            end
            ftype = lower(f.Filetype);
            if strcmp(ftype, 'head')
                if ~isempty(strfind(f.TypeOfVolumes, '_FUNC'))
                    ftype = 'hfunc';
                end
            end
            switch (ftype)
                case {'ava', 'glm', 'hfunc', 'map', 'vmp'}
                    cv_addtolist(BVQXti.h.uiCStats.MLHandle, f, vn);
                    BVQXti.c.incb = false;
                    BVQXtool(0, 'setcstats');
                case {'olt'}
                    try
                        BVQXti.lut.ClearObject;
                    catch
                        % do nothing
                    end
                    BVQXti.lut = f;
                    BVQXti.c.incb = false;
                    BVQXtool(0, 'setslicepos');
                case {'dmr', 'fmr', 'hdr', 'vmr', 'vtc'}
                    cv_addtolist(BVQXti.h.uiCVar.MLHandle, f, vn);
                    if any(strcmpi(f.Filetype, {'dmr', 'fmr', 'vtc'}))
                        BVQXti.h.uiCTmpPosSl.Max = f.NrOfVolumes;
                        BVQXti.h.uiCTmpPosSl.Value = 1;
                        BVQXti.h.uiCTmpPosSl.SliderStep = ...
                            (1 / (f.NrOfVolumes - 1)) * [1, 10];
                        BVQXti.h.uiCTmpPosSl.Enable = 'on';
                        BVQXti.h.uiCTmpPosEd.String = '1';
                    else
                        BVQXti.h.uiCTmpPosSl.Value = 1;
                        BVQXti.h.uiCTmpPosSl.Enable = 'off';
                        BVQXti.h.uiCTmpPosEd.String = '1';
                    end
                    BVQXti.c.incb = false;
                    BVQXtool(0, 'setcvar');
            end

        % close currently selected file
        case {'closefile'}
            
        % set current CStat map
        case {'setcstatmap'}
            BVQXti.fcfg.StatsVarIdx = [];
            BVQXti.h.fMainFig.SetGroupEnabled('SLdNVMP', 'off');
            if strcmpi(BVQXti.h.uiCStats.Enable, 'off')
                BVQXti.h.fMainFig.SetGroupEnabled('SLoaded', 'off');
                return;
            end
            BVQXti.h.fMainFig.SetGroupEnabled('SLoaded', 'on');
            stvi = BVQXti.h.uiCStatCont.Value;
            BVQXti.fcfg.StatsVarIdx = stvi;
            if ~isempty(stvi)
                switch (lower(BVQXti.fcfg.StatsVar.Filetype))
                    case {'glm'}
                        mvals = BVQXti.fcfg.StatsVar.GetVolume(stvi);
                    case {'head'}
                        mvals = BVQXti.fcfg.StatsVar.GetVolume(stvi);
                    case {'map'}
                        mvals = BVQXti.fcfg.StatsVar.GetVolume(1);
                    case {'vmp'}
                        mvals = [];
                        BVQXti.h.fMainFig.SetGroupEnabled('SLdNVMP', 'on');
                        BVQXti.fcfg.StatsVarkThr = ...
                            BVQXti.fcfg.StatsVar.Map(stvi).ClusterSize;
                        BVQXti.fcfg.StatsVarThr = [ ...
                            BVQXti.fcfg.StatsVar.Map(stvi).LowerThreshold, ...
                            BVQXti.fcfg.StatsVar.Map(stvi).UpperThreshold];
                        BVQXti.h.Stats.PosTail.Value = double(mod( ...
                            BVQXti.fcfg.StatsVar.Map(stvi).ShowPositiveNegativeFlag, 2) > 0);
                        BVQXti.h.Stats.NegTail.Value = double( ...
                            BVQXti.fcfg.StatsVar.Map(stvi).ShowPositiveNegativeFlag > 1);
                        switch (BVQXti.fcfg.StatsVar.Map(stvi).Type)
                            case {1}
                                BVQXti.fcfg.StatsVarPar = {'t', ...
                                    BVQXti.fcfg.StatsVar.Map(stvi).DF1, 0};
                            case {2}
                                BVQXti.fcfg.StatsVarPar = {'F', ...
                                    BVQXti.fcfg.StatsVar.Map(stvi).DF1, ...
                                    BVQXti.fcfg.StatsVar.Map(stvi).DF2};
                            case {3}
                                BVQXti.fcfg.StatsVarPar = {'r', ...
                                    BVQXti.fcfg.StatsVar.Map(stvi).DF1, 0};
                            otherwise
                                BVQXti.fcfg.StatsVarPar{1} = '!';
                        end
                    otherwise
                        mvals = [];
                        BVQXti.fcfg.StatsVarThr = [0, 1];
                end
            else
                mvals = [];
                BVQXti.fcfg.StatsVarThr = [0, 1];
            end
            if any(isinf(BVQXti.fcfg.StatsVarThr) | isnan(BVQXti.fcfg.StatsVarThr))
                BVQXti.fcfg.StatsVarThr = [0.5, 1];
            end
            set(BVQXti.h.Stats.LThresh, 'String', ...
                sprintf('%.3f', BVQXti.fcfg.StatsVarThr(1)));
            set(BVQXti.h.Stats.UThresh, 'String', ...
                sprintf('%.3f', BVQXti.fcfg.StatsVarThr(2)));
            set(BVQXti.h.Stats.kThresh, 'String', ...
                sprintf('%d', floor(BVQXti.fcfg.StatsVarkThr)));
            if ~isempty(mvals)
                mvals = abs(mvals(:));
                mvals(mvals == 0) = [];
                upp = minmaxmean(mvals, 5);
                BVQXti.fcfg.StatsVarThr = [ ...
                    max(eps, upp(3) + 0.25 * sqrt(upp(6)) - upp(2) * sqrt(eps)), ...
                    upp(2) + eps * upp(2)];
            end
            if BVQXti.fcfg.StatsVarAlpha < 0 && ...
                numel(BVQXti.fcfg.StatsVarIdx) > 1
                BVQXti.fcfg.StatsVarAlpha = -2 / numel(BVQXti.fcfg.StatsVarIdx);
            end
            BVQXtool(0, 'setslicepos');

            
        % set current CStats
        case {'setcstats'}
            hi = BVQXti.h.uiCStats.Value;
            hu = BVQXti.h.uiCStats.UserData;
            if hi > 0 && ...
                hi <= size(hu, 1)
                v = hu{hi, 4};
                if numel(v.MapNames) > 0
                    BVQXti.h.uiCStatCont.String = v.MapNames;
                    BVQXti.h.uiCStatCont.Value = 1;
                    BVQXti.h.uiCStatCont.Enable = 'on';
                    BVQXti.fcfg.StatsVar = v;
                    BVQXti.fcfg.StatsVarIdx = 1;
                else
                    BVQXti.h.uiCStatCont.String = 'none';
                    BVQXti.h.uiCStatCont.Value = 1;
                    BVQXti.h.uiCStatCont.Enable = 'off';
                    BVQXti.fcfg.StatsVar = [];
                    BVQXti.fcfg.StatsVarIdx = [];
                end
                BVQXtool(0, 'setcstatmap');
            end
            
        % set current CVar
        case {'setcvar'}
            hi = BVQXti.h.uiCVar.Value;
            hu = BVQXti.h.uiCVar.UserData;
            if hi > 0 && ...
                hi <= size(hu, 1)
                BVQXti.fcfg.SlicesVar = hu{hi, 4};
                if isBVQXfile(hu{hi, 4}, 'dmr') || ...
                    isBVQXfile(hu{hi, 4}, 'fmr') || ...
                    isBVQXfile(hu{hi, 4}, 'vtc')
                    BVQXti.h.fMainFig.SetGroupEnabled('VIsTemp', 'on');
                else
                    BVQXti.h.fMainFig.SetGroupEnabled('VIsTemp', 'off');
                end
                BVQXtool(0, 'setslicepos');
            end
            
        % SPM image to VMR
        case {'spmcreatevmr'}
            
            % request image file
            [spmimgfile, spmimgpath] = uigetfile( ...
               {'*.hdr', 'Analyze 7.5 images'; '*.nii', 'NIftI images'}, ...
                'Please select image file to convert to VMR...', ...
                '', 'MultiSelect', 'off');
            if isequal(spmimgfile, 0) || ...
                isequal(spmimgpath, 0) || ...
                exist([spmimgpath '/' spmimgfile], 'file') ~= 2
                return;
            end
            spmimgfile = strrep(strrep([spmimgpath '/' spmimgfile], ...
                '\', '/'), '//', '/');
            
            % some options
            tl = cell(1, 1);
            try
                th = BVQXfile(spmimgfile);
                tl{1} = th;
                doflip = {};
                if th.NIIFileType < 1 && ...
                    all(th.DataHist.OriginSPM == 0)
                    doflip = questdlg('Is this a flipped image?', ...
                        'BVQXtool request...', 'Yes', 'No', 'Cancel', 'Yes');
                    if strcmpi(doflip, 'cancel')
                        th.ClearObject;
                        return;
                    end
                    if strcmpi(doflip, 'yes')
                        doflip = {'flipped', true};
                    else
                        doflip = {'flipped', false};
                    end
                end
                th.ClearObject;
                tl{1} = [];
            catch
                clearbvqxobjects(tl);
                errordlg('Error reading selected file.', 'BVQXtool error', 'modal');
                return;
            end
            
            % what target space
            ismni = questdlg('Is the source in MNI space (create MNI VMR)?', ...
                'BVQXtool request...', 'Yes', 'No', 'Cancel', 'Yes');
            if strcmpi(ismni, 'cancel')
                return;
            end
            if strcmpi(ismni, 'yes')
                ismni = {'ismni', true};
            else
                ismni = {'ismni', false};
            end
            
            % target filename
            [vmrfile, vmrpath] = uiputfile( ...
               {'*.vmr', 'BrainVoyager VMR files'}, ...
                'Please specify the target VMR filename...', '');
            if isequal(vmrfile, 0) || ...
                isequal(vmrpath, 0)
            end
            vmrfile = strrep(strrep([vmrpath '/' vmrfile], ...
                '\', '/'), '//', '/');
            
            % try creation
            try
                th = createvmr(spmimgfile, struct(ismni{:}, doflip{:}));
                tl{1} = th;
                th.SaveAs(vmrfile);
                disp('VMR successfully written:');
                disp(['  => ' th.FilenameOnDisk]);
            catch
                clearbvqxobjects(tl);
                errordlg('Error creating / saving VMR.', 'BVQXtool error', 'modal');
                return;
            end
            clearbvqxobjects(tl);
            
            
        % spmX_xxxx.img -> VMP conversion
        case {'spmmapimportvmp'}
            
            % conversion
            try
                vmp = cell(1, 1);
                vmp{1} = importvmpfromspms;
                
                % request target file(s)
                [vmpfile, vmppath] = uiputfile( ...
                   {'*.vmp', 'BrainVoyager Volume MaP files'}, ...
                    'Please specify the target VMP filename...', '');
                if isequal(vmpfile, 0) || ...
                    isequal(vmppath, 0)
                    clearbvqxobjects(vmp);
                    return;
                end
                
                % save VMPs
                if iscell(vmppath)
                    vmppath = vmppath{1};
                end
                if iscell(vmpfile)
                    vmpfile = vmpfile{1};
                end
                vmp{1}.SaveAs(strrep( ...
                    [strrep(vmppath, '\', '/') '/' vmpfile], '//', '/'));
            catch
                clearbvqxobjects(vmp);
                errordlg(['Error converting spmX_xxxx.img -> VMP: ' lasterr], ...
                    'BVQXtool error', 'modal');
                return;
            end
            disp('spmX_xxxx.img -> VMP conversion OK.');
            disp(sprintf('  => %s', vmp{1}.FilenameOnDisk));
            clearbvqxobjects(vmp);
            
        % SPM.mat -> PRT conversion
        case {'spmmat2prt'}
            
            % request SPM.mat file
            [spmmatfile, spmmatpath] = uigetfile( ...
               {'SPM*.mat', 'SPM design matrix files'}, ...
                'Please select SPM.mat file to convert to PRT...', ...
                'SPM*.mat', 'MultiSelect', 'off');
            if isequal(spmmatfile, 0) || ...
                isequal(spmmatpath, 0) || ...
                exist([spmmatpath '/' spmmatfile], 'file') ~= 2
                return;
            end
            
            % request protocol target file(s)
            [prtfile, prtpath] = uiputfile( ...
               {'*.prt', 'BrainVoyager Protocol files'}, ...
                'Please specify the first target filename...', 'SPM*.prt');
            if isequal(prtfile, 0) || ...
                isequal(prtpath, 0)
                return;
            end
            
            % conversion
            try
                spmmatfile = strrep(strrep([spmmatpath '/' spmmatfile], ...
                    '\', '/'), '//', '/');
                prtfile = strrep(strrep([prtpath '/' prtfile], ...
                    '\', '/'), '//', '/');
                [p, ps] = spmmat2prt(spmmatfile, prtfile);
                if numel(ps) > 1
                    ss = 's';
                else
                    ss = '';
                end
            catch
                errordlg(['Error converting SPM.mat -> PRT: ' lasterr], ...
                    'BVQXtool error', 'modal');
                return;
            end
            disp(sprintf('SPM.mat -> PRT conversion (%d session%s) OK.', ...
                numel(ps), ss));
            for sc = 1:numel(ps)
                disp(sprintf('  => %s', ps{sc}.FilenameOnDisk));
            end
            clearbvqxobjects(ps);
            
        % SPM.mat -> SDM conversion
        case {'spmmat2sdm'}
            
            % request SPM.mat file
            [spmmatfile, spmmatpath] = uigetfile( ...
               {'SPM.mat', 'SPM design matrix files'}, ...
                'Please select SPM.mat file to convert to SDM...', ...
                'SPM*.mat', 'MultiSelect', 'off');
            if isequal(spmmatfile, 0) || ...
                isequal(spmmatpath, 0) || ...
                exist([spmmatpath '/' spmmatfile], 'file') ~= 2
                return;
            end
            
            % request protocol target file(s)
            [sdmfile, sdmpath] = uiputfile( ...
               {'*.sdm', 'BrainVoyager Design matrix files'}, ...
                'Please specify the first target filename...', 'SPM*.sdm');
            if isequal(sdmfile, 0) || ...
                isequal(sdmpath, 0)
            end
            
            % conversion
            try
                spmmatfile = strrep(strrep([spmmatpath '/' spmmatfile], ...
                    '\', '/'), '//', '/');
                sdmfile = strrep(strrep([sdmpath '/' sdmfile], ...
                    '\', '/'), '//', '/');
                [r, rs] = spmmat2sdm(spmmatfile, sdmfile);
                if numel(rs) > 1
                    ss = 's';
                else
                    ss = '';
                end
            catch
                errordlg(['Error converting SPM.mat -> SDM: ' lasterr], ...
                    'BVQXtool error', 'modal');
                return;
            end
            disp(sprintf('SPM.mat -> SDM conversion (%d session%s) OK.', ...
                numel(rs), ss));
            for sc = 1:numel(rs)
                disp(sprintf('  => %s', rs{sc}.FilenameOnDisk));
            end
            clearbvqxobjects(rs);
            
        % var list
        case {'varlist'}
            
            % return internal varlist
            varargout{1} = BVQXti.w;
            
        % about dialog
        case {'about'}
            BVQXti.c.incb = true;
            abt = helpdlg(sprintf( ...
                ['BVQXtool: a Matlab GUI for visualizing BrainVoyager QX\n' ...
                 'files (VMR, VTC, FMR) as well as SPM/AFNI files, part of\n' ...
                 'the BVQXtools package.\n\n' ...
                 'Please visit http://wiki.brainvoyager.com/ for more info.']), ...
                 'BVQXtool - About');
            set(abt, 'WindowStyle', 'modal');
            uiwait(abt);
            BVQXti.c.incb = false;
            
        % init BVQXtool window
        case {'initwindow'}
            try
                % make sure the figure is available !
                fMainFig = BVQXfigure('BVQXtool_MainFig');
                if ~isBVQXfigure(fMainFig);
                    return;
                end
                fHandles = fMainFig.TagStruct;
                
                % get current handles struct
                h = BVQXti.h;
                h.fMainFig = fMainFig;
                h.uiCVar = fHandles.DD_BVQXtool_varlist;
                h.uiCStats = fHandles.DD_BVQXtool_statlist;
                h.uiCStatCont = fHandles.LB_BVQXtool_statmaps;
                h.uiCStatClust = fHandles.LB_BVQXtool_clusters;
                h.uiCStatClusTb = fHandles.ED_BVQXtool_clusters;
                h.uiCTmpPosEd = fHandles.ED_BVQXtool_TempPos;
                h.uiCTmpPosSl = fHandles.SL_BVQXtool_TempPos;
                h.uiCTmpPosSl.Max = 2;
                h.uiCTmpPosSl.Min = 1;
                h.uiCTmpPosSl.Value = 1;
                h.Progress = fHandles.PB_BVQXtool_mainpbar;
                h.Progress.Visible = 'off';
                h.fChild = [];
                BVQXti.h = h;

                % here comes the real code after the check
                
                % plot into TCPlot axes
                plot(mlhandle(fHandles.AX_BVQXtool_TC_Plot), (1:120)', zeros(120, 1));
                
                % add stuff to three views
                fcfg = struct;
                fcfg.cPos = [0, 0, 0];
                fcfg.frame = [128, 128, 128; -127.99, -127.99, -127.99];
                fcfg.trans = eye(4);
                fcfg.dirorder = {'sag', 'cor', 'tra'};
                fcfg.h = struct;
                fcfg.ShowLines = true;
                fcfg.ShowZoom = 0;
                fcfg.SlicesPos = [ ...
                     432, 456, 688, 712; ...
                     692, 456, 948, 712; ...
                     692, 196, 948, 452];
                fcfg.ZSlicePos = [434, 198, 946, 710];
                fcfg.SlicesVar = [];
                fcfg.StatsVar = [];
                fcfg.StatsVarIdx = [];
                fcfg.StatsVarThr = [0, 1];
                fcfg.StatsVarPar = {'t', 1, 1};
                fcfg.StatsVarAlpha = 1;
            
                % get axes objects
                ax12 = mlhandle(fHandles.AX_BVQXtool_Slice_SAG);
                set(ax12, 'Units', 'pixels');
                lax11 = line([0; 1], [0.5; 0.5], 'Color', [0, 0, 1], 'Parent', ax12);
                lax12 = line([0.5; 0.5], [0; 1], 'Color', [0, 0, 1], 'Parent', ax12);
                set(ax12, 'Units', 'normalized', 'Visible', 'off');
                
                ax22 = mlhandle(fHandles.AX_BVQXtool_Slice_COR);
                set(ax22, 'Units', 'pixels');
                lax21 = line([0; 1], [0.5; 0.5], 'Color', [0, 0, 1], 'Parent', ax22);
                lax22 = line([0.5; 0.5], [0; 1], 'Color', [0, 0, 1], 'Parent', ax22);
                set(ax22, 'Units', 'normalized', 'Visible', 'off');
                
                ax32 = mlhandle(fHandles.AX_BVQXtool_Slice_TRA);
                set(ax32, 'Units', 'pixels');
                lax31 = line([0; 1], [0.5; 0.5], 'Color', [0, 0, 1], 'Parent', ax32);
                lax32 = line([0.5; 0.5], [0; 1], 'Color', [0, 0, 1], 'Parent', ax32);
                set(ax32, 'Units', 'normalized', 'Visible', 'off');
            
                ax42 = mlhandle(fHandles.AX_BVQXtool_Slice_Zoom);
                set(ax42, 'Units', 'pixels');
                lax41 = line([0; 1], [0.5; 0.5], 'Color', [0, 0, 1], 'Parent', ax42);
                lax42 = line([0.5; 0.5], [0; 1], 'Color', [0, 0, 1], 'Parent', ax42);
                set(ax42, 'Units', 'normalized', 'Visible', 'off');
                set([ax12, ax22, ax32, ax42], 'XTick', [], 'YTick', []);
                
                % add some text properties
                h.Coord.VEdY = mlhandle(fHandles.ED_BVQXtool_BVSY);
                h.Coord.VEdZ = mlhandle(fHandles.ED_BVQXtool_BVSZ);
                h.Coord.VEdX = mlhandle(fHandles.ED_BVQXtool_BVSX);
                h.Coord.TEdY = mlhandle(fHandles.ED_BVQXtool_TALY);
                h.Coord.TEdZ = mlhandle(fHandles.ED_BVQXtool_TALZ);
                h.Coord.TEdX = mlhandle(fHandles.ED_BVQXtool_TALX);
                h.Coord.SVal = fHandles.TX_BVQXtool_SValues;
                sethandle(BVQXti.tio.imCor, ...
                    get(mlhandle(fHandles.IM_BVQXtool_Slice_COR), 'Children'));
                h.CorLineX = lax21;
                h.CorLineY = lax22;
                sethandle(BVQXti.tio.imSag, ...
                    get(mlhandle(fHandles.IM_BVQXtool_Slice_SAG), 'Children'));
                h.SagLineX = lax11;
                h.SagLineY = lax12;
                sethandle(BVQXti.tio.imTra, ...
                    get(mlhandle(fHandles.IM_BVQXtool_Slice_TRA), 'Children'));
                h.TraLineX = lax31;
                h.TraLineY = lax32;
                sethandle(BVQXti.tio.imSlZ, ...
                    get(mlhandle(fHandles.IM_BVQXtool_Slice_Zoom), 'Children'));
                h.ZoomLineX = lax41;
                h.ZoomLineY = lax42;
                h.Stats.kThresh = mlhandle(fHandles.ED_BVQXtool_kExtThresh);
                h.Stats.LThresh = mlhandle(fHandles.ED_BVQXtool_LowerThresh);
                h.Stats.UThresh = mlhandle(fHandles.ED_BVQXtool_UpperThresh);
                h.Stats.PosTail = fHandles.CB_BVQXtool_PositivStat;
                h.Stats.NegTail = fHandles.CB_BVQXtool_NegativStat;
                h.Stats.PThresh = fHandles.DD_BVQXtool_StatSetP;
                h.Stats.UsekThr = fHandles.CB_BVQXtool_kExtThresh;
                h.Stats.MNI2TAL = fHandles.CB_BVQXtool_MNI2TAL;
                h.Stats.TDClient = fHandles.CB_BVQXtool_TDClient;
                h.Interpolate = fHandles.CB_BVQXtool_Interpolate;
                
                % some more handles
                h.TCPlot = fHandles.AX_BVQXtool_TC_Plot;
                fMainFig.SetGroupEnabled('SLoaded', 'off');
                fMainFig.SetGroupEnabled('SLdNVMP', 'off');
                
                % and settings
                fHandles.DD_BVQXtool_StatSetP.String = ...
                    {'0.05'; '0.01'; '0.005'; '0.002'; '0.001'; '0.0005'; '0.0001'};
                
                % populate LUT list
                try
                    luts = findfiles(bvqxtools_path('lut'), '*.olt', 'depth=1');
                    for lc = 1:numel(luts)
                        [lutp, lutf] = fileparts(luts{lc});
                        lutf = strrep(lutf, '_', ' ');
                        uimenu( ...
                            mlhandle(fHandles.UIM_LUTList), ...
                            'Label', [upper(lutf(1)) lutf(2:end)], ...
                            'Callback', ['BVQXtool(0, ''openfile'', ''' ...
                            luts{lc} ''');']);
                    end
                catch
                    fHandles.UIM_LUTList.Visible = 'off';
                end
                
                % make figure visible
                h.uiCVar.UserData = cell(0, 4);
                h.uiCStats.UserData = cell(0, 4);
                BVQXti.fcfg = fcfg;
                BVQXti.h = h;
                fMainFig.Visible = 'on';
                fMainFig.KeyPressFcn = @bt_handlekpe;
                fMainFig.WindowButtonDownFcn = 'BVQXtool(0, ''mainwindowbtdown'');';
                fMainFig.WindowButtonMotionFcn = 'BVQXtool(0, ''mainwindowbtmove'');';
                fMainFig.WindowButtonUpFcn = 'BVQXtool(0, ''mainwindowbtup'');';
                drawnow;
                
            catch
                % do nothing
            end
            
        % otherwise
        otherwise
            error( ...
                'BVQXtool:BadCall', ...
                'Unsupported command to UI call.' ...
            );
    end
    
% no args
elseif nargin == 0
    if nargout > 0
        varargout{1} = BVQXtool(0, 'createobj');
    end
    
    % try loading all objects currently in workspace
    hasvmr = false;
    bvqxo = BVQXfile(0, 'objects');
    for oc = 2:numel(bvqxo)
        try
            if any(strcmpi(bvqxo(oc).S.Extensions{1}, ...
                {'dmr', 'fmr', 'glm', 'vmp', 'vmr', 'vtc'}))
                BVQXtool(0, 'openfile', BVQXfile(bvqxo(oc).L));
                if strcmpi(bvqxo(oc).S.Extensions{1}, 'vmr')
                    hasvmr = true;
                end
            end
        catch
            % do nothing
        end
    end
    if ~hasvmr
        try
            BVQXtool(0, 'openfile', [bvqxtools_path('colin'), filesep, 'colin.vmr']);
        catch
            % do nothing
        end
    end
    return;
    
% other arguments
else
end



% bt_createobj
function o = bt_createobj
    o = struct;
    o.h = [];
    o.hc = [];
    o.i = 0;
    o.v = {};
% end of function o = bt_createobj

% bt_handlekpe
function bt_handlekpe(src, evnt)
    try
        BVQXtool(0, 'mainwindowkeypress', src, evnt);
    catch
        % do nothing
    end
% end of function bt_handlekpe

% cv_addtolist
function cv_addtolist(hc, f, n)
    [fn{1:3}] = fileparts(f.FilenameOnDisk);
    if isempty(fn{2})
        fn{2} = 'untitled';
        fn{3} = ['.' f.Filetype];
    end
    s = get(hc, 'String');
    u = get(hc, 'UserData');
    if ~iscell(s)
        s = cellstr(s);
    end
    s = s(:);
    if numel(s) == 1 && ...
        strcmp(s{1}, 'empty')
        s(1) = [];
    end
    s{end+1} = [fn{2}, fn{3}];
    u(end + 1, :) = {s{end}, lower(fn{3}(2:end)), n, f};
    set(hc, 'String', s, 'UserData', u, 'Enable', 'on', 'Value', size(u, 1));
% end of function cv_addtolist

% cv_removefromlist
function cv_removefromlist(hc, v)
    s = get(hc, 'String');
    u = get(hc, 'UserData');
    x = get(hc, 'Value');
    e = 'on';
    if ~iscell(s)
        s = cellstr(s);
    end
    s = s(:);
    if numel(s) == 1 && ...
        strcmp(s{1}, 'empty')
        return;
    end
    vs = struct(v);
    for c = 1:size(u, 1)
        ts = struct(u{c, 4});
        if vs.L == ts.L
            u(c, :) = [];
            s(c) = [];
            if x >= c
                x = -1;
            end
            if isempty(s)
                s = {'empty'};
                x = 1;
                e = off;
            end
            set(hc, 'String', s, 'UserData', u, 'Enable', e, 'Value', x);
        end
    end
% end of function cv_removefromlist
